package com.thinkingcoder.tcconfig.client.config;

import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.ApplicationContext;

import com.thinkingcoder.tcconfig.client.listener.TcConfigChangeEvent;

import lombok.extern.slf4j.Slf4j;

/**
 * tc config service impl.
 */
@Slf4j
public class TcConfigServiceImpl implements TcConfigService {

    Map<String, String> config;
    ApplicationContext applicationContext;

    public TcConfigServiceImpl(ApplicationContext applicationContext, Map<String, String> config) {
        this.config = config;
        this.applicationContext = applicationContext;
    }

    @Override
    public String[] getPropertyNames() {
        return this.config.keySet().toArray(new String[0]);
    }

    @Override
    public String getProperty(String name) {
        return this.config.get(name);
    }

    @Override
    public void onChange(TcConfigChangeEvent changeEvent) {
        Set<String> updatedKeys = calcChangeKeys(this.config, changeEvent.getConfig());

        if (updatedKeys == null || updatedKeys.isEmpty()) {
            log.info("[TC-CONFIG] calcChangeKeys return empty, ignore update.");
            return;
        }

        this.config = changeEvent.getConfig();
        if (!this.config.isEmpty()) {
            log.info("[TC-CONFIG] Fire an EnvironmentChangeEvent with updatedKeys : {} .", updatedKeys);
            this.applicationContext.publishEvent(new EnvironmentChangeEvent(updatedKeys));
        }
    }

    private Set<String> calcChangeKeys(Map<String, String> oldConfigs, Map<String, String> newConfigs) {
        if (oldConfigs == null || oldConfigs.isEmpty()) {
            return newConfigs.keySet();
        }
        if (newConfigs == null || newConfigs.isEmpty()) {
            return oldConfigs.keySet();
        }
        // 计算出 key对应的值有变化、新增key 的情况
        Set<String> news = newConfigs.keySet().stream().filter(key -> !newConfigs.get(key).equals(oldConfigs.get(key)))
            .collect(Collectors.toSet());
        // 计算出 key被移除 的情况
        oldConfigs.keySet().stream().filter(key -> !newConfigs.containsKey(key)).forEach(news::add);
        return news;
    }

}
